﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Configuration;
using System.IO;
using System.Xml;
using System.Globalization;

namespace Umbrella.Whs.Properties
{
    /// <summary>
    /// this settings provider stores the settings into the
    /// duplicating application folder. there is now difference
    /// between application and user settings.
    /// 
    /// settings provider name: Umbrella.Whs.Properties.ApplicationFolderSettingsProvider
    /// </summary>
    public sealed class ApplicationFolderSettingsProvider : SettingsProvider
    {
        private readonly log4net.ILog _log = log4net.LogManager.GetLogger(typeof(ApplicationFolderSettingsProvider));
		
        public override string ApplicationName
        {
            get;
            set;
        }

        public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
        {
            if (string.IsNullOrEmpty(name))
                name = GetType().FullName;

            base.Initialize(name, config);
        }

        private static FileInfo GetConfigFileByContext(SettingsContext context)
        {
            // handle design time loading of settings
            if (System.ComponentModel.LicenseManager.UsageMode == System.ComponentModel.LicenseUsageMode.Designtime)
            {
                var fi = new FileInfo(Path.Combine(Path.GetTempPath(), "DesignTimeConfig.tmp"));

                if (fi.Exists)
                {
                    fi.Delete();

                    fi.Refresh();
                }

                return fi;
            }

            // determine settings file
            var groupName = (string)context["GroupName"];
            var key = context["SettingsKey"] as string;

            var sectionName = groupName;

            if (!string.IsNullOrEmpty(key))
            {
                sectionName = string.Format("{0}.{1}", sectionName, key);
            }

            return new FileInfo(ApplicationFolders.Instance.DuplicatedDir.FullName + "\\" + sectionName + ".config");
        }

        public override SettingsPropertyValueCollection GetPropertyValues(SettingsContext context, SettingsPropertyCollection collection)
        {
            var fi = GetConfigFileByContext(context);

            if (_log.IsDebugEnabled)
                _log.Debug("Loading settings file: " + fi.FullName + " ...");

            // load xml
            try
            {
                var xml = new XmlDocument();
                var noSettings = !fi.Exists;
	
                if (!noSettings)
                {
                    using (var s = fi.OpenText())
                    {
                        xml.Load(s);
                    }
                }
	
                // gather values
                var ret = new SettingsPropertyValueCollection();
	
                foreach (SettingsProperty p in collection)
                {
                    var spv = new SettingsPropertyValue(p);
	
                    spv.IsDirty = false;
	
                    if (noSettings)
                        spv.SerializedValue = p.DefaultValue ?? string.Empty;
                    else
                    {
                        var elem = xml.SelectSingleNode("//" + p.Name) as XmlElement;
	
                        if (elem == null)
                            spv.SerializedValue = (p.DefaultValue == null ? string.Empty : p.DefaultValue.ToString());
                        else
                            spv.SerializedValue = elem.InnerText;
                    }
	
                    ret.Add(spv);

                    if (_log.IsDebugEnabled)
                        _log.DebugFormat("  {0} = {1}", spv.Name, spv.SerializedValue as string);
                }
	
                // finalize
                if (noSettings)
                    _log.Info("Loaded default settings for file: " + fi.FullName);
                else
                    _log.Info("Loaded settings file: " + fi.FullName);
	
                return ret;
            }
            catch (Exception e)
            {
                _log.Fatal("Failed to load settings file: " + fi.FullName, e);

                throw;
            }
        }

        public override void SetPropertyValues(SettingsContext context, SettingsPropertyValueCollection collection)
        {
            var fi = GetConfigFileByContext(context);

            if (_log.IsDebugEnabled)
                _log.Debug("Saving settings file: " + fi.FullName + " ...");

            try
            {
                using (var tw = fi.CreateText())
                {
                    using (var xw = new XmlTextWriter(tw))
                    {
                        xw.Formatting = Formatting.Indented;

                        xw.WriteStartDocument();
                        xw.WriteStartElement("settings");
                        {
                            xw.WriteAttributeString("version", UmbrellaVersion.VersionId.ToString());
	
                            foreach (SettingsPropertyValue spv in collection)
                            {
                                var val = (spv.SerializedValue == null ? string.Empty : spv.SerializedValue.ToString());

                                xw.WriteElementString(spv.Name, val);

                                if (_log.IsDebugEnabled)
                                    _log.DebugFormat("  {0} = {1}", spv.Name, val);
                            }
                        }
                        xw.WriteEndElement();
                        xw.WriteEndDocument();
                    }
                }
	
                // done
                _log.Info("Saved settings file: " + fi.FullName);
            }
            catch (Exception e)
            {
                _log.Fatal("Failed to save settings file: " + fi.FullName, e);

                throw;
            }
        }
    }
}